#include "mainwindow.h"
#include "widgets/utoast.h"
#include "modelview/ulistview.h"
#include "widgets/umenu.h"
#include "widgets/uslider.h"
#include "widgets/upushbutton.h"
#include "widgets/ucommonbutton.h"
#include "widgets/uedgebutton.h"
#include "widgets/ulineedit.h"
#include "dialog/uaboutdialog.h"
#include "dialog/uloadingdialog.h"
#include "uapplication.h"
#include "style/uproxystyle.h"
#include "style/upalette.h"
#include "uwidgetutils.h"
#include "titleswidget.h"
#include "widgets/utitlebar.h"
#include "datetimewidget.h"
#include "viewwidget.h"
#include "editwidget.h"
#include "buttonwidget.h"
#include "transferwidget.h"
#include "loopplaywidget.h"
#include "progressbarwidget.h"
#include "homewidget.h"

#include <message/UMessageDispatcher>
#include <thread/UThread>
#include <UHttpClient>
#include "encrypt/uaesencrypt.h"
#include "encrypt/ursaencrypt.h"
#include "encrypt/urc2encrypt.h"

#include <QBoxLayout>
#include <QIcon>
#include <QTimer>
#include <QApplication>
#include <QStandardItemModel>
#include <QStackedWidget>
#include <QDebug>
#include <QScrollArea>
#include <QLabel>
#include <QActionGroup>
#include <QFile>
#include <QMouseEvent>

MainWindow::MainWindow(QWidget* parent)
    : UMainWindow(parent)
    , m_listview(new UListView(this))
    , m_mainWidget(new QStackedWidget(this))
    , m_stackedWidget(new QStackedWidget(this))
    , m_titlesWidget(new TitlesWidget(this))
    , m_homeBtn(new UCommonButton("Home", this))
    , m_seachEdit(new ULineEdit(this))
{
    initUI();
    initTest();
    initAnimation();
}

MainWindow::~MainWindow()
{
}

void MainWindow::initUI()
{
    initMenu();
    m_listview->initListView();
    m_listview->setItemHeight(45);

    m_seachEdit->setMinimumHeight(35);
    m_seachEdit->addLeftAction(QIcon::fromTheme("utk_search"), QSize(26, 26));
    m_seachEdit->setPlaceholderText(tr("Search"));

    m_homeBtn->setEnabled(false);
    m_homeBtn->setButtonFeature(UCommonButtonOption::PlainButton);
    m_homeBtn->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    m_homeBtn->setBackgroundRole(UPalette::Highlight);
    m_homeBtn->setForegroundRole(UPalette::Highlight);
    m_homeBtn->setRadius(8);
    m_homeBtn->setRadiuPosition(RadiuPosition::All);
    m_homeBtn->setIcon(QIcon::fromTheme("utk_home"));
    m_homeBtn->setMinimumHeight(35);

    if (titleBar())
    {
        titleBar()->insertWidget(2, m_homeBtn);
    }

    QHBoxLayout* mainLayout = new QHBoxLayout;
    mainLayout->setSpacing(0);
    QWidget* centerWidget = new QWidget(this);
    centerWidget->setLayout(mainLayout);
    setCentralWidget(m_stackedWidget);

    m_leftWidget = new QWidget(this);
    QVBoxLayout* vlayout = new QVBoxLayout(m_leftWidget);
    vlayout->setContentsMargins(0,0,0,0);
    vlayout->addWidget(m_seachEdit);
    vlayout->addWidget(m_listview);
    m_edgeButton = new UEdgeButton(this);
    m_edgeButton->setExpand(true);
    m_edgeButton->setVisible(false);
    mainLayout->addWidget(m_leftWidget, 1);
    mainLayout->addWidget(m_edgeButton);
    mainLayout->addSpacing(5);
    mainLayout->addWidget(m_mainWidget, 4);

    HomeWidget* home = new HomeWidget(this);
    home->mainLayout()->insertWidget(1, m_titlesWidget);
    m_titlesWidget->setMinimumHeight(630);
    m_stackedWidget->addWidget(home);
    m_stackedWidget->addWidget(centerWidget);

    initListView();
    initContent();
    initConnection();
    m_listview->setCurrentIndex(m_listview->model()->index(0, 0));

    m_loadingDialog = new LoadingDialog(this);
    m_loadingDialog->setIcon(QIcon::fromTheme("utk_loading"));
    m_loadingDialog->setIconSize(QSize(66, 66));
    m_loadingDialog->setText(tr("Loading..."));
}

void MainWindow::initMenu()
{
    QActionGroup* group = new QActionGroup(this);
    QActionGroup* languageGroup = new QActionGroup(this);
    UMenu* menu = new UMenu(this);
    QAction* about = menu->addAction(tr("About"));
    about->setIcon(QIcon::fromTheme("about"));
    m_actionList.append(about);
    menu->addSeparator();
    UMenu* menu1 = new UMenu(this);
    menu1->setTitle(tr("theme"));

    QAction* light = menu1->addAction(tr("light"));
    m_actionList.append(light);
    light->setCheckable(true);
    group->addAction(light);
    QAction* dark = menu1->addAction(tr("dark"));
    m_actionList.append(dark);
    dark->setCheckable(true);
    group->addAction(dark);
    m_actionList.append(menu->addMenu(menu1));

    UMenu* languageMenu = new UMenu(this);
    languageMenu->setTitle(tr("language"));
    QAction* chinese = languageMenu->addAction(tr("Chinese"));
    m_actionList.append(chinese);
    chinese->setCheckable(true);
    languageGroup->addAction(chinese);
    QAction* english = languageMenu->addAction(tr("English"));
    m_actionList.append(english);
    english->setCheckable(true);
    languageGroup->addAction(english);
    m_actionList.append(menu->addMenu(languageMenu));

    QAction* exit = menu->addAction(tr("Exit"));
    m_actionList.append(exit);
    addMenu(menu);

    if (uApp->applicationTheme() == UTheme::DarkTheme)
    {
        dark->setChecked(true);
    }
    else
    {
        light->setChecked(true);
    }

    if (uApp->currentLanguage() == QLocale::Language::Chinese)
    {
        chinese->setChecked(true);
    }
    else
    {
        english->setChecked(true);
    }

    connect(about, &QAction::triggered, this, &MainWindow::handleAbout);
    connect(exit, &QAction::triggered, this, &MainWindow::handleQuit);
    connect(dark, &QAction::triggered, this, [ = ]()
    {
        if (auto style = qobject_cast<UProxyStyle*>(uApp->style()))
        {
            style->setTheme(UTheme::DarkTheme);
            uApp->setPalette(style->standardPalette());
        }
    });
    connect(light, &QAction::triggered, this, [ = ]()
    {
        if (auto style = qobject_cast<UProxyStyle*>(uApp->style()))
        {
            style->setTheme(UTheme::LightTheme);
            uApp->setPalette(style->standardPalette());
        }
    });
    connect(chinese, &QAction::triggered, this, [ = ]()
    {
        uApp->changeTranslator(QLocale::Language::Chinese);
    });
    connect(english, &QAction::triggered, this, [ = ]()
    {
        uApp->changeTranslator(QLocale::Language::English);
    });
}

void MainWindow::initTest()
{
    UMessageDispatcher::instance()->registerEvent(1, std::bind(&MainWindow::test, this, std::placeholders::_1));
    auto res = std::make_shared<UMessageResult>();
    UMessageDispatcher::instance()->sendMessage(1, std::make_shared<UMessage>(1, 1, "test"), std::move(res));
    int code = UMessageDispatcher::instance()->postMessage(1, std::make_shared<UMessage>(1, 1, "test"));
    qDebug() << res->msgCode << res->msgResult << code;

    QThread* thread = UThread::createFuture<std::shared_ptr<UMessageResult>>(std::bind(&MainWindow::test, this, std::make_shared<UMessage>()));
    connect(thread, &QThread::finished, this, [ = ]()
    {
        auto s = dynamic_cast<QThreadCreateTaskThread<std::shared_ptr<UMessageResult>>*>(sender());
        qDebug() << "UThread finished" << s->getResult()->msgResult;
    });
    thread->start();

    QTimer::singleShot(3000, this, [ = ]()
    {
        this->showFloatMessage(true, "mainwindow show!!!");
    });
#if 0
    UHttpClient::instance()->downloadFile(QUrl("https://image.baidu.com/search/down?tn=download&word=download&ie=utf8&fr=detail&url=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2%2F58a111d9bc05d.jpg&thumburl=https%3A%2F%2Fimg0.baidu.com%2Fit%2Fu%3D1598850878%2C59814561%26fm%3D253%26fmt%3Dauto%26app%3D120%26f%3DJPEG%3Fw%3D1280%26h%3D800"), "123.jpg", [ = ](int status)
    {
        qInfo() << status;
    });
#endif

    UAESEncrypt encrypt(UAESEncrypt::AES_192, UAESEncrypt::AES_CBC, UAESEncrypt::AES_PKCS7);
    auto result = encrypt.encrypt("123456", "qwertyqwerty1234qwertyqw", "qwertyqwerty1234");
    qInfo() << "UAESEncrypt::encrypt:" << result.toBase64() << encrypt.decrypt(result, "qwertyqwerty1234qwertyqw", "qwertyqwerty1234");

    URSAEncrypt rsaEncrypt;
    if (!QFile::exists("public_key.pem"))
    {
        rsaEncrypt.generateRSAKeys(2048, "public_key.pem", "private_key.pem");
    }
    std::string str = "6708120ab2f56928980555033baca13d";
    std::string filename = "public_key.pem";
    std::string prifilename = "private_key.pem";

    auto data = rsaEncrypt.encryptByPubkeyFile(QByteArray::fromStdString(str), filename);
    qInfo() << "DDDD====:" << QByteArray::fromRawData(data.data(), data.size()).toBase64();
    qInfo() <<  rsaEncrypt.decryptByPrikeyFile(data, prifilename);

    unsigned char key[] = {106, 51, 25, 141, 157, 142, 23, 111, 234, 159, 187, 154, 215, 34, 37, 205};
    unsigned char iv[] = {135, 186, 133, 136, 184, 149, 153, 144};
    URC2Encrypt RC2Encrypt;
    auto array = RC2Encrypt.encrypt(QByteArray::fromStdString(str), key, iv);
    qInfo() << "RC2Encrypt" << array;
    qInfo() << "RC2Dncrypt" << RC2Encrypt.decrypt(array, key, iv);
}

void MainWindow::showFloatMessage(bool isOK, const QString &message)
{
    if (message.isEmpty())
        return;

    if (toolTip && toolTip->isVisible())
        return;

    toolTip = new UToast(this);
    toolTip->setIcon(isOK ? QIcon(":/images/success_20px.svg") : QIcon(":/images/warning_30px.svg"));
    toolTip->setText(message);
    QPoint point = QPoint((width() - toolTip->sizeHint().width()) / 2,
                          (height() - toolTip->sizeHint().height() - 30));
    toolTip->show();
    toolTip->move(point);

    QTimer::singleShot(3000, this, [ = ]()
    {
        toolTip->close();
        toolTip->deleteLater();
        toolTip = Q_NULLPTR;
    });
}

void MainWindow::initListView()
{
    const QVector<QString> textList =
    {
        QObject::tr("Label"), QObject::tr("Button"), QObject::tr("LineEdit"), QObject::tr("datetime"),
        QObject::tr("developing"), QObject::tr("developing 1"), QObject::tr("developing 2"), QObject::tr("developing 3"),
        QObject::tr("developing 4"), QObject::tr("developing 5"), QObject::tr("developing 6"), QObject::tr("developing 7"),
        QObject::tr("developing 8"), QObject::tr("developing 9"), QObject::tr("developing 10")
    };

    const QList<QString> iconList =
    {
        "utk_label", "utk_button", "utk_lineedit", "utk_datetime",
        "utk_db", "utk_network", "utk_flag", "utk_lampbulb",
        "utk_message", "utk_notice", "utk_painter", "utk_settings",
        "utk_statistics", "utk_renew", "title"
    };

    m_model = new QStandardItemModel(this);
    m_listview->setModel(m_model);

    for (int i = 0; i < textList.size(); i++)
    {
        QStandardItem* item = new QStandardItem(textList.at(i));
        item->setIcon(QIcon::fromTheme(iconList[i]));
        item->setSizeHint(QSize(160, 50));
        m_model->appendRow(item);
    }
}

void MainWindow::initContent()
{
    UWidget* labelWidget = new UWidget(this);
    auto slider = new USlider(Qt::Horizontal, labelWidget);
    slider->setGeometry(600, 400, 200, 40);
    QScrollArea* area = new QScrollArea(labelWidget);
    area->setGeometry(100, 100, 400, 400);
    QLabel* label = new QLabel("this is label", area);
    label->setFixedSize(600, 600);
    area->setWidgetResizable(true);
    area->setWidget(label);
    m_mainWidget->addWidget(labelWidget);
    m_listWidget.insert(0, labelWidget);

    ButtonWidget* buttonWidget = new ButtonWidget(this);
    m_mainWidget->addWidget(buttonWidget);
    m_listWidget.insert(1, buttonWidget);

    EditWidget* comboxLineEditWidget = new EditWidget(this);
    m_mainWidget->addWidget(comboxLineEditWidget);
    m_listWidget.insert(2, comboxLineEditWidget);

    DateTimeWidget* dateTimeWidget = new DateTimeWidget(this);
    m_mainWidget->addWidget(dateTimeWidget);
    m_listWidget.insert(3, dateTimeWidget);

    ViewWidget* viewWidget = new ViewWidget(this);
    m_mainWidget->addWidget(viewWidget);
    m_listWidget.insert(4, viewWidget);

    TransferWidget* transferWidget = new TransferWidget(this);
    m_mainWidget->addWidget(transferWidget);
    m_listWidget.insert(5, transferWidget);

    LoopPalyWidget* loopPalyWidget = new LoopPalyWidget(this);
    m_mainWidget->addWidget(loopPalyWidget);
    m_listWidget.insert(6, loopPalyWidget);

    ProgressBarWidget* pgBarWidget = new ProgressBarWidget(this);
    m_mainWidget->addWidget(pgBarWidget);
    m_listWidget.insert(7, pgBarWidget);
}

void MainWindow::initConnection()
{
    connect(m_seachEdit, &ULineEdit::textChanged, this, [ = ](const QString & text)
    {
        QList<QStandardItem*> items = m_model->findItems(text, Qt::MatchContains);
        for (int i = 0; i < m_model->rowCount(); ++i)
        {
            auto item = m_model->item(i);
            m_listview->setRowHidden(i, !items.contains(item));
        }
    });

    connect(m_listview, &UListView::clicked, this, &MainWindow::onChangeWidget);

    connect(m_homeBtn, &QPushButton::clicked, this, [ = ]()
    {
        m_stackedWidget->setCurrentIndex(0);
        m_homeBtn->setEnabled(false);
    });

    connect(m_titlesWidget, &QListView::clicked, this, &MainWindow::onChangeCenterWidget);

    connect(m_edgeButton, &UEdgeButton::expandChanged, this, [ = ](bool isExpand)
    {
        if (isExpand) {
           int width = m_propertyAnimation.startValue().toInt();
           handleAnimation(0, width);
        } else {
            handleAnimation(m_listview->width(), 0);
        }
    });
}

std::shared_ptr<UMessageResult> MainWindow::test(std::shared_ptr<UMessage> msg)
{
    qDebug() << msg->msgId << msg->msgType << msg->msgData << QThread::currentThreadId();
    return std::make_shared<UMessageResult>(true, "aaa");
}

void MainWindow::showLoadingDialog(bool isVisible, const QString &text)
{
    if (isVisible && m_loadingDialog->isVisible())
    {
        return;
    }

    if (isVisible)
    {
        m_loadingDialog->start(600);
    }
    else
    {
        m_loadingDialog->stop();
    }

    m_loadingDialog->setText(text);
    m_loadingDialog->setVisible(isVisible);
}

void MainWindow::changeEvent(QEvent* event)
{
    if (event->type() == QEvent::LanguageChange)
    {
        const QVector<QString> textList = {tr("About"), tr("light"), tr("dark"), tr("theme"),
                                           tr("Chinese"), tr("English"), tr("language"), tr("Exit")
                                          };
        for (int i = 0; i < m_actionList.size(); i++)
        {
            m_actionList[i]->setText(textList[i]);
        }
        const QVector<QString> leftList =
        {
            QObject::tr("Label"), QObject::tr("Button"), QObject::tr("LineEdit"), QObject::tr("datetime"),
            QObject::tr("developing"), QObject::tr("developing 1"), QObject::tr("developing 2"), QObject::tr("developing 3"),
            QObject::tr("developing 4"), QObject::tr("developing 5"), QObject::tr("developing 6"), QObject::tr("developing 7"),
            QObject::tr("developing 8"), QObject::tr("developing 9"), QObject::tr("developing 10")
        };
        for (int i = 0; i < leftList.size(); i++)
        {
            m_model->item(i, 0)->setText(leftList[i]);
        }
        m_seachEdit->setPlaceholderText(tr("Search"));
    }
    else
    {
        UMainWindow::changeEvent(event);
    }
}

void MainWindow::handleAbout()
{
    UAboutDialog dialog(this);
    dialog.setAppIcon(UWidgetUtils::generateQRcode(uApp->organizationDomain(), QSize(96, 96)));
    dialog.setAppVersion(QString("Version: %1").arg(uApp->applicationVersion()));
    dialog.setAppName(uApp->applicationName());
    dialog.setAppDescribe("this is a utkwidget");
    dialog.setAppHomePage(uApp->organizationDomain());
    dialog.exec();
}

void MainWindow::handleQuit()
{
    qApp->quit();
}

void MainWindow::onChangeWidget(const QModelIndex &index)
{
    if (m_listWidget.contains(index.row()))
    {
        m_mainWidget->setCurrentWidget(m_listWidget[index.row()]);
    }
}

void MainWindow::onChangeCenterWidget(const QModelIndex &index)
{
    m_stackedWidget->setCurrentIndex(1);
    m_homeBtn->setEnabled(true);

    QModelIndex currentIndex = m_listview->model()->index(index.row(), 0);
    if (currentIndex.isValid())
    {
        m_listview->setCurrentIndex(currentIndex);
        onChangeWidget(currentIndex);
    }
}

void MainWindow::onGlobalMouseEvent(QMouseEvent *event)
{
   if (0 == m_stackedWidget->currentIndex())
   {
       return;
   }
   if (!m_edgeButton->isExpand())
   {
       return;
   }
   auto globalRect = QRect(mapToGlobal(m_leftWidget->geometry().topLeft()), m_leftWidget->size());
   globalRect.setWidth(globalRect.width() + 20);
   m_edgeButton->setVisible(globalRect.contains(event->globalPos()));
}

void MainWindow::initAnimation()
{
    m_propertyAnimation.setPropertyName("width");
    m_propertyAnimation.setTargetObject(m_leftWidget);
    m_propertyAnimation.setDuration(500);
    connect(&m_propertyAnimation, &QPropertyAnimation::valueChanged, this, [ = ](const QVariant & value)
    {
        m_leftWidget->setFixedWidth(value.toInt());
    });
}

void MainWindow::handleAnimation(qreal startValue, qreal endValue)
{
    if (m_propertyAnimation.state() != QPropertyAnimation::Stopped)
    {
        m_propertyAnimation.stop();
    }
    m_propertyAnimation.setStartValue(startValue);
    m_propertyAnimation.setEndValue(endValue);
    m_propertyAnimation.start();
}
